package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.job.XxlJobTast;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.ArticleFreemarkerService;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.model.article.dtos.*;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.vos.ArticleCommnetVo;
import com.heima.model.article.vos.ApArticleVo;
import com.heima.model.article.vos.BehaviorVo;
import com.heima.model.article.vos.CommentArticleVo;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.message.Message;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.wemedia.dtos.CommentPageDto;
import com.heima.model.wemedia.dtos.StatisticsDto;
import com.heima.utils.common.DateUtils;
import com.heima.model.wemedia.dtos.CommentDto;
import com.heima.model.wemedia.dtos.ManageDto;
import com.heima.utils.thread.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Transactional(rollbackFor = Exception.class)
@Service
@Slf4j
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;

    @Autowired
    private ArticleFreemarkerService articleFreemarkerService;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private HotArticleService hotArticleService;
    @Autowired
    private XxlJobTast xxlJobTast;

    /**
     * 加载文章列表
     *
     * @param dto
     * @param type
     * @return
     */
    @Override
    public ResponseResult load(ArticleHomeDto dto, Short type) {
        //1.数据校验
        if (dto == null && type == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.数据处理
        //2.1 处理size
        if (dto.getSize() == null || dto.getSize() <= 0) {
            dto.setSize(10);
        } else {
            dto.setSize(Math.min(dto.getSize(), 50));
        }
        //2.2 处理id
        if (StringUtils.isEmpty(dto.getTag())) dto.setTag(ArticleConstants.DEFAULT_TAG);
        //2.3 处理时间
        if (dto.getMaxBehotTime() == null) dto.setMaxBehotTime(new Date());
        if (dto.getMinBehotTime() == null) dto.setMinBehotTime(new Date());
        //2.4 处理type
        if (type == null) type = ArticleConstants.LOADTYPE_LOAD_MORE;
        //3.业务操作
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, type);
        //4.响应结果
        return ResponseResult.okResult(apArticles);
    }

    /**
     * 保存或者修改文章
     *
     * @param articleDto
     * @return
     */
    @Override
    public ResponseResult<Long> saveOrUpdateArticle(ArticleDto articleDto) {
        //1.校验数据
        if (articleDto == null && StringUtils.isEmpty(articleDto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.封装数据
        ApArticle article = new ApArticle();
        BeanUtils.copyProperties(articleDto, article);
        //3.请求类型
        if (articleDto.getId() == null) {
            //3.1保存
            //插入文章表
            save(article);
            //插入内容表
            ApArticleContent apArticleContent = new ApArticleContent();
            apArticleContent.setContent(articleDto.getContent());
            apArticleContent.setArticleId(article.getId());
            apArticleContentMapper.insert(apArticleContent);
            //插入文章配置表
            ApArticleConfig apArticleConfig = new ApArticleConfig(article.getId());
            apArticleConfigMapper.insert(apArticleConfig);
        } else {
            //更新文章表
            updateById(article);
            //更新内容表
            ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, article.getId()));
            apArticleContent.setContent(articleDto.getContent());
            apArticleContentMapper.updateById(apArticleContent);
        }
        //一个事物不是更好？
        articleFreemarkerService.buildArticleToMinIO(article, articleDto.getContent());
        //3.2 修改
        return ResponseResult.okResult(article.getId());
    }

    /**
     * 根据articleId获取ESVO
     * @param id
     * @return
     */
    @Override
    public ResponseResult getESVoById(Long id) {
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        ApArticle article = getById(id);

        if (article == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, id));
        SearchArticleVo searchArticleVo = new SearchArticleVo();
        BeanUtils.copyProperties(article, searchArticleVo);
        searchArticleVo.setContent(apArticleContent.getContent());
        return ResponseResult.okResult(searchArticleVo);
    }

    /**
     * 加载文章行为
     * @param dto
     * @return
     */
    @Override
    public ResponseResult loadBehavior(LoadBehaviorDto dto) {
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        Map<Object, Object> objectObjectMap = cacheService.hGetAll(ThreadLocalUtil.get() + "_" + dto.getArticleId() + "_behavior");
        Set<Object> keySet = objectObjectMap.keySet();
        BehaviorVo behaviorVo = new BehaviorVo();
        if (keySet.contains("collection")) behaviorVo.setIscollection(true);
        if (keySet.contains("like")) behaviorVo.setIslike(true);
        if (keySet.contains("unlike")) behaviorVo.setIsunlike(true);
        Set<String> ids = cacheService.zRangeAll(ThreadLocalUtil.get() + "_" + dto.getArticleId() + "_follow");
        if (ids.contains(dto.getAuthorId().toString())) {
            behaviorVo.setIsfollow(true);
        }
        return ResponseResult.okResult(behaviorVo);
    }

    /**
     * 查询五天内的所有文章
     * @param date
     * @return
     */
    @Override
    public List<ApArticle> findArticleListByLast5days(Date date) {
        return apArticleMapper.findArticleListByLast5days(date);
    }

    /**
     * 加载首页
     * @param dto
     * @param loadtypeLoadMore
     * @return
     */
    @Override
    public ResponseResult loadFirstPage(ArticleHomeDto dto, Short loadtypeLoadMore) {
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        String resList = cacheService.get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
        if (StringUtils.isNotEmpty(resList)) {
            List<HotArticleVo> hotArticleVos = JSON.parseArray(resList, HotArticleVo.class);
            hotArticleVos = hotArticleVos.stream().limit(30).collect(Collectors.toList());
            return ResponseResult.okResult(hotArticleVos);
        }
        return load(dto, loadtypeLoadMore);
    }

    /**
     * 时事热点新闻计算
     *@param messageStr
     */
    @Override
    public void updateScore(String messageStr) {
        if (StringUtils.isEmpty(messageStr)) {
            return;
        }
        Message message = JSON.parseObject(messageStr, Message.class);
        ApArticle apArticle = getById(message.getArticleId());
        Integer oldScore = hotArticleService.computeScore(apArticle);
        Integer newScore = updateHotArticle(apArticle, message);
        Integer finalScore = ((newScore - oldScore) < 0 ? (newScore - oldScore) : (newScore - oldScore) * 3) + oldScore;
        //封装一个VO
        HotArticleVo hotArticleVo = new HotArticleVo();
        BeanUtils.copyProperties(apArticle, hotArticleVo);
        hotArticleVo.setScore(finalScore);
        //更新redis
        updateRedis(hotArticleVo, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());
        updateRedis(hotArticleVo, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
    }

    /**
     * @param dto
     * @description: 根据创建时间和分页条件查询上架的文章评论概览
     * @param: dto
     * @return: com.heima.model.common.dtos.ResponseResult
     * @author: liyong
     * @date: 2023/06/28 17:05
     */
    @Override
    public PageResponseResult pageCommentArticle(ManageDto dto) {


        dto.checkParam();

        System.out.println("dto.getPage() = " + dto.getPage());
        System.out.println("dto.getSize() = " + dto.getSize());
        System.out.println("dto.getBeginDate() = " + dto.getBeginDate());
        System.out.println("dto.getEndDate() = " + dto.getEndDate());

        IPage<CommentArticleVo> iPage = apArticleMapper.pageCommentArticle(new Page(dto.getPage(), dto.getSize()), dto);

        PageResponseResult pageResult = new PageResponseResult();
        pageResult.setCode(200);
        pageResult.setErrorMessage(AppHttpCodeEnum.SUCCESS.getErrorMessage());
        pageResult.setData(iPage.getRecords());
        pageResult.setCurrentPage((int) iPage.getCurrent());
        pageResult.setSize(((int) iPage.getSize()));
        pageResult.setTotal(((int) iPage.getTotal()));

        return pageResult;
    }

    /**
     * @param dto
     * @description: 修改文章可评论状态
     * @param: dto
     * @return: com.heima.model.common.dtos.ResponseResult
     * @author: liyong
     * @date: 2023/06/28 21:54
     */
    @Override
    public ResponseResult updateStatus(CommentDto dto) {


        ApArticleConfig apArticleConfig = apArticleConfigMapper.selectOne(
                Wrappers.<ApArticleConfig>lambdaQuery().eq(ApArticleConfig::getArticleId,dto.getArticleId()));

        if (Objects.isNull(apArticleConfig)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        switch (dto.getOperation()) {
            case 0:
                //修改文章关闭评论状态
                apArticleConfig.setIsComment(false);
                //删除mongo所有文章评论,在wemedia操作

                //将文章评论数置为0
                ApArticle apArticle = apArticleMapper.selectById(apArticleConfig.getArticleId());
                if (apArticle != null) {
                    apArticle.setComment(0);
                    apArticleMapper.updateById(apArticle);
                }
                break;
            case 1:
                //修改文章开启评论状态
                apArticleConfig.setIsComment(true);
                break;
            default:
                log.error("未知的参数异常operation:{}", dto.getOperation());
                throw new CustomException(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST);
        }
        apArticleConfigMapper.updateById(apArticleConfig);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 查询点赞和收藏
     *
     * @param wmUserId
     * @param beginDate
     * @param endDate
     * @return
     */
    @Override
    public ResponseResult queryLikesAndConllections(Integer wmUserId, Date beginDate, Date endDate) {
        Map map = apArticleMapper.queryLikesAndConllections(wmUserId, beginDate, endDate);
        return ResponseResult.okResult(map);
    }

    /**
     * 分页查询 图文统计
     *
     * @param dto
     * @return
     */
    @Override
    public PageResponseResult newPage(StatisticsDto dto) {
        //类型转换
        Date beginDate = DateUtils.stringToDate(dto.getBeginDate());
        Date endDate = DateUtils.stringToDate(dto.getEndDate());
        //检查参数
        dto.checkParam();
        //分页查询
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<ApArticle> lambdaQueryWrapper = Wrappers.<ApArticle>lambdaQuery()
                .eq(ApArticle::getAuthorId, dto.getWmUserId())
                .between(ApArticle::getPublishTime, beginDate, endDate)
                .select(ApArticle::getId, ApArticle::getTitle, ApArticle::getLikes, ApArticle::getCollection, ApArticle::getComment, ApArticle::getViews);

        lambdaQueryWrapper.orderByDesc(ApArticle::getPublishTime);

        page = page(page, lambdaQueryWrapper);

        PageResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());

        return responseResult;
    }


    @Override
    public ResponseResult findArticleComment(ApArticleCommentDto apArticleCommentDto) {
        List<ArticleCommnetVo> list=apArticleMapper.findArticleComment(apArticleCommentDto);
        Integer totalCount=apArticleMapper.findTotal(apArticleCommentDto);
        PageResponseResult result = new PageResponseResult(apArticleCommentDto.getPage(), apArticleCommentDto.getSize(), totalCount);
        result.setData(list);
        result.setErrorMessage(AppHttpCodeEnum.SUCCESS.getErrorMessage());

        return result;

    }

    /**
     * 开启和关闭文章可评论功能
     *
     * @param apArticleOpenCommentDto
     * @return
     */
    @Override
    public ResponseResult openComment(ApArticleOpenCommentDto apArticleOpenCommentDto) {
        if (apArticleOpenCommentDto==null||apArticleOpenCommentDto.getArticleId()==null||apArticleOpenCommentDto.getOperation()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        ApArticleConfig apArticleConfig = apArticleConfigMapper
                .selectOne(Wrappers.<ApArticleConfig>lambdaQuery()
                        .eq(ApArticleConfig::getArticleId, apArticleOpenCommentDto.getArticleId()));
        //开启评论功能
        if (apArticleOpenCommentDto.getOperation()==1){
           apArticleConfig.setIsComment(true);
           apArticleConfigMapper.updateById(apArticleConfig);
        }else {
            //关闭评论功能
            //删除评论的输入
            update(Wrappers.<ApArticle>lambdaUpdate().eq(ApArticle::getId,apArticleOpenCommentDto.getArticleId())
                    .set(ApArticle::getComment,0));
            //设置评论设置为0
            apArticleConfig.setIsComment(false);
            apArticleConfigMapper.updateById(apArticleConfig);
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    private void updateRedis(HotArticleVo hotArticleVo, String name) {
        String res = cacheService.get(name);
        if (StringUtils.isEmpty(res)) {
            xxlJobTast.refreshHotArticle();
        }
        res = cacheService.get(name);
        List<HotArticleVo> hotArticleVos = StringUtils.isEmpty(res) ? new ArrayList<>() : JSON.parseArray(res, HotArticleVo.class);
        hotArticleVos = hotArticleVos.stream().filter(hotArticleVoOld -> !hotArticleVoOld.getId().equals(hotArticleVo.getId())).collect(Collectors.toList());
        hotArticleVos.add(hotArticleVo);
        hotArticleVos = hotArticleVos.stream().sorted(((o1, o2) -> o2.getScore() - o1.getScore())).limit(40).collect(Collectors.toList());
        cacheService.set(name, JSON.toJSONString(hotArticleVos));
    }


    /**
     * 更新文章数据
     *
     * @param apArticle
     * @param messageStr
     */
    private Integer updateHotArticle(ApArticle apArticle, Message messageStr) {
        apArticle.setCollection(apArticle.getCollection() == null ? messageStr.getCollect() : apArticle.getCollection() + messageStr.getCollect());
        apArticle.setViews(apArticle.getViews() == null ? messageStr.getView() : apArticle.getViews() + messageStr.getView());
        apArticle.setLikes(apArticle.getLikes() == null ? messageStr.getLike() : apArticle.getLikes() + messageStr.getLike());
        apArticle.setComment(apArticle.getComment() == null ? messageStr.getComment() : apArticle.getComment() + messageStr.getComment());
        updateById(apArticle);
        return hotArticleService.computeScore(apArticle);
    }


    /**
     * 分页查询文章数据
     *
     * @param dto
     * @return com.heima.model.common.dtos.ResponseResult
     * @Description
     * @Author YangJiangPing
     * @Date 15:50 2023/6/28
     * @Param [dto]
     */
    @Override
    public PageResponseResult findNewsComments(CommentPageDto dto) {
        //1: 参数校验
        if (dto == null) {
            return (PageResponseResult) PageResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2.数据处理
        //2.1 处理size
        if (dto.getSize() == null || dto.getSize() <= 0) {
            dto.setSize(10);
        } else {
            dto.setSize(Math.min(dto.getSize(), 50));
        }
        //3: 查询文章
//        Page<ApArticleVo> page = new Page<>(dto.getPage(),dto.getSize());
        IPage<ApArticleVo> page = new Page<>(dto.getPage(),dto.getSize());
        //3.2: 最小时间
        String begin = dto.getBeginDate() + " 00:00:00";
        String end = dto.getEndDate() + " 23:59:59";
        dto.setBeginDate(begin);
        //3.3: 最大时间
        dto.setEndDate(end);
        //3.4: 查询
        IPage<ApArticleVo> apArticleVoPage = apArticleMapper.commentPageInf(page, dto);
        long total = page.getTotal();
        int i = Integer.parseInt(String.valueOf(total));

        //4: 设置返回值
        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), i);
        result.setCode(AppHttpCodeEnum.SUCCESS.getCode());
        result.setErrorMessage(AppHttpCodeEnum.SUCCESS.getErrorMessage());
        result.setData(apArticleVoPage.getRecords());

        System.out.println(page.getTotal());
        System.out.println(apArticleVoPage.getTotal());
        return result;
    }
}
